// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This file is part of CodingEditor.
// Note:	This project is derived from Peter Project
//			(hosted on sourceforge and codeplex)
//
// Copyright (c) 2008-2009, CE Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


namespace CE.Main
{
	using System;
	using System.Diagnostics;
	using System.Drawing;
	using System.IO;
	using System.Text.RegularExpressions;
	using System.Windows.Forms;

	using CE.API;

	using WeifenLuo.WinFormsUI.Docking;

	public sealed partial class CommandPrompt : DockContent, ICEPluginTab
	{
		#region Fields
		private readonly string initLocation;

		private bool m_Command;
		private ICEPluginHost m_Host;
		private StreamWriter m_Writer;

		#endregion Fields

		#region Constructors

		public CommandPrompt(string location)
		{
			Initialize();
			if (location != null)
				initLocation = "cd " + location;
		}

		#endregion Constructors

		#region Delegates

		public delegate void UpdateOutputCallback(string text);

		#endregion Delegates

		#region Properties

		public bool AbleToCopy
		{
			get { return true; }
		}

		public bool AbleToCut
		{
			get { return false; }
		}

		public bool AbleToDelete
		{
			get { return false; }
		}

		public bool AbleToPaste
		{
			get { return true; }
		}

		public bool AbleToRedo
		{
			get { return false; }
		}

		public bool AbleToSave
		{
			get { return true; }
		}

		public bool AbleToSelectAll
		{
			get { return true; }
		}

		public bool AbleToUndo
		{
			get { return false; }
		}

		public string FileName
		{
			get { return ""; }
		}

		public ICEPluginHost Host
		{
			get { return m_Host; }

			set { m_Host = value; }
		}

		public bool NeedsSaving
		{
			get { return false; }
		}

		public string Selection
		{
			get { return rtbOutput.SelectedText; }
		}

		#endregion Properties

		#region Methods

		public bool CloseTab()
		{
			Close();
			return true;
		}

		public void Copy()
		{
			rtbOutput.Copy();
		}

		public void Cut()
		{
		}

		public void Delete()
		{
		}

		public void Duplicate()
		{
		}

		public bool FindNext( Regex reg, bool searchUp)
		{
			Match m = reg.Match(rtbOutput.Text, rtbOutput.SelectionStart);
			if (m.Success) {
				rtbOutput.Select(m.Index, m.Length);
				return true;
			}
			return false;
		}

		public void MarkAll( Regex reg)
		{
		}

		public void Paste()
		{
			if (Clipboard.ContainsText()) {
				cmbInput.Text = Clipboard.GetText();
			}
		}

		public void Print(bool showDialog)
		{
		}

		public void Redo()
		{
		}

		public void ReplaceAll( Regex reg,  string replaceWith)
		{
		}

		public void ReplaceNext( Regex reg,  string replaceWith, bool searchUp)
		{
		}

		/// <summary>
		/// Runs the given command...
		/// </summary>
		/// <param name="command">Command to run.</param>
		public void RunCommand(string command)
		{
			if (command != null ) {
				if (command == "cls") {
					rtbOutput.Clear();
					return;
				}
				m_Writer.WriteLine(command);
				m_Command = true;
				if (!cmbInput.Items.Contains(command)) {
					cmbInput.Items.Add(command);
				}
				cmbInput.Text = "";
				m_Writer.WriteLine("cd");
			}
		}

		/// <summary>
		/// Runs the given Script...
		/// </summary>
		/// <param name="script">Script to run (Commands should be separated by a new line '\n').</param>
		/// <param name="workingDirectory">Directory to run script.</param>
		public void RunScript(string script, string workingDirectory)
		{
			int index = workingDirectory.IndexOf(":\\");
			if (index > 0) {
				m_Writer.WriteLine(workingDirectory.Substring(0, index + 1));
			}
			m_Writer.WriteLine("cd " + workingDirectory);
			string[] commands = Regex.Split(script, Environment.NewLine);
			foreach (string command in commands) {
				if (!string.IsNullOrEmpty(command)) {
					m_Writer.WriteLine(command);
				}
			}
		}

		public void Save()
		{
			m_Host.SaveAsCurrentFile(this);
		}

		public void SaveAs( string filePath)
		{
			rtbOutput.SaveFile(filePath);
		}

		public void SelectAll()
		{
			rtbOutput.SelectAll();
		}

		public void SelectWord(int line, int offset, int wordLeng)
		{
		}

		public void Undo()
		{
		}

		private void CommandPrompt_FormClosed(object sender, FormClosedEventArgs e)
		{
			Dispose(true);
		}

		private void CommandPrompt_Load(object sender, EventArgs e)
		{
			StartCommandPrompt();
			cmbInput.Focus();
			RunCommand(initLocation);
		}

		private void HandleError(object sender, DataReceivedEventArgs e)
		{
			if (!string.IsNullOrEmpty(e.Data)) {
				rtbOutput.Invoke(new UpdateOutputCallback(UpdateError), new object[] {e.Data});
			}
		}

		private void HandleOutput(object sender, DataReceivedEventArgs e)
		{
			if (!string.IsNullOrEmpty(e.Data)) {
				rtbOutput.Invoke(new UpdateOutputCallback(UpdateOutput), new object[] {e.Data});
			}
		}

		private void Initialize()
		{
			InitializeComponent();
			Load += CommandPrompt_Load;
			TabText = "Command Prompt";
			m_Command = false;
			cmbInput.KeyDown += InputKeyPress;
			rtbOutput.GotFocus += rtbOutput_GotFocus;
		}

		private void InputKeyPress(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter) {
				RunCommand(cmbInput.Text);
			}
		}

		private void StartCommandPrompt()
		{
			var cmd = new Process
			{
				StartInfo =
				{
					FileName = "cmd.exe",
					WindowStyle = ProcessWindowStyle.Hidden,
					CreateNoWindow = true,
					UseShellExecute = false,
					RedirectStandardError = true,
					RedirectStandardInput = true,
					RedirectStandardOutput = true
				}
			};

			cmd.OutputDataReceived += HandleOutput;
			cmd.ErrorDataReceived += HandleError;

			cmd.Start();
			m_Writer = cmd.StandardInput;
			cmd.BeginErrorReadLine();
			cmd.BeginOutputReadLine();
		}

		private void UpdateError(string text)
		{
			int start = rtbOutput.TextLength;
			rtbOutput.AppendText(text + Environment.NewLine);
			rtbOutput.Select(start, text.Length);
			rtbOutput.SelectionColor = Color.Red;
			rtbOutput.Select(rtbOutput.TextLength, 0);
			rtbOutput.ScrollToCaret();
		}

		private void UpdateOutput(string text)
		{
			if (!m_Command && text.IndexOf(">cd") == text.Length - 3) {
				return;
			}

			int start = rtbOutput.TextLength;

			rtbOutput.AppendText(text + Environment.NewLine);

			if (m_Command) {
				rtbOutput.Select(start, text.Length);
				rtbOutput.SelectionColor = Color.Yellow;
				rtbOutput.Select(rtbOutput.TextLength, 0);
				m_Command = false;
			}

			rtbOutput.ScrollToCaret();
		}

		private void cmbInput_Click(object sender, EventArgs e)
		{
			if (cmbInput.SelectionLength != cmbInput.Text.Length)
				cmbInput.SelectAll();
			else
				cmbInput.Select(0, 1); // unselect
		}

		private void rtbOutput_GotFocus(object sender, EventArgs e)
		{
			cmbInput.Focus();
		}

		#endregion Methods
	}
}